--
-- 03/06/2012
-- demouc_m && dourle_a
--   

checks = {}

MEMBER = false

--- Called when assignement detected
-- This is a callback assigned in checks
-- like a = b
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_ASSIGN(text)
   if STATIC == nil and MEMBER == false and ASSIGN ~= nil then
      warn("A;A Variable named : " .. ASSIGN .. " is declared and assigned in the same line.")
   end
end

checks["ASSIGN"] = c_ASSIGN

function c_SIZEOF(text)
   SIZEOF = 1
end

checks["SIZEOF"] = c_SIZEOF

--- Called when semicolon detected
-- This is a callback assigned in checks
-- like ;
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_SEMICOLON(text)
   if RETURN ~= nil then
      RETURN = nil
      warn("(;No opening PAREN after return keyword.")
   end
end

checks["SEMICOLON"] = c_SEMICOLON

--- Called when qualifier detected
-- This is a callback assigned in checks
-- like const, static, inline..
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_QUALIFIER(text, parent)
   if not c.isQualifier(text) then
      warn("Q;A qualifier is used: " .. text .. " without being known?!?")
   end
   if text == c.static and parent == "FUNC_DEF" then static = true; return; end
   if text == c.static then STATIC = 1 end
end

checks["QUALIFIER"] = c_QUALIFIER

--- Called when newline detected
-- This is a callback assigned in checks
-- like \n
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_NEWLINE(text, parent)
   if MEMBER == false and TYPEStoADD ~= nil then
      TYPES[TYPEStoADD.id] = TYPEStoADD.obj
   end
   MEMBER = false
   if ASSIGN ~= nil then
      TABCHECK[FILE][LINE] = 1
   end
   SIZEOF = nil
   ASSIGN = nil
   STATIC = nil
   if FUNCTION_LEN ~= nil then FUNCTION_LEN = FUNCTION_LEN + 1 end
   TYPEStoADD = nil
end

checks["NEWLINE"] = c_NEWLINE

--- Called when member detected
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_MEMBER(text, parent)
   ASSIGN = nil
   MEMBER = true
end

checks["MEMBER"] = c_MEMBER

--- Called when a function declaration is detected
-- This is a callback assigned in checks
-- like int main()
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_FUNC_DEF(text)
   if not string.onlyLower(text) then
      warn("U;The function name: " .. text .. " contains uppercase characters.")
   end
   enterFunc(text, static)
   static = false
end

checks["FUNC_DEF"] = c_FUNC_DEF

--- Called when a word is detected
-- This is a callback assigned in checks
-- like variale, macro..
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_WORD(text)
   if FILE:ends(".h") and include_double == 1 then
      if text ~= nil and text ~= string.gsub(FILE:upper():sub(0, FILE:len() - 2), ".*/", "") .. "_H_" then
	 warn("I;The double inclusion: is not valid, it should be " ..   string.gsub(FILE:upper():sub(0, FILE:len() - 2), ".*/", "") .. "_H_")
      end
      include_double = 2
      if include_d then
	 include_d = false 
	 return
      end
   else
      if include_d then
	 include_d = false 
	 return
      end
      if ASSIGN then ASSIGN = text end
      if FUNCTION ~= nil and ASSIGN ~= nil and not string.onlyLower(text) then
	 warn("U;A variable name: " .. text .. " contains uppercase characters in function: " .. FUNCTION.. ".")
      end
      if FUNC_PROTO == nil and FUNCTION == nil and STRUCT == nil and not text:starts("g_") then
	 warn("N;A global variable: " .. text .. " has a bad name. Should be g_" .. text .. ".")
      end
   end
end
checks["WORD"] = c_WORD

--- Called when a opening bracket is detected in function declaration
-- This is a callback assigned in checks
-- like (
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_FPAREN_OPEN(text, parent)
   if parent == "FUNC_DEF" then FUNC_DEF = 0 end
   if parent == "FUNC_PROTO" then FUNC_PROTO = 0 end
end

checks["FPAREN_OPEN"] = c_FPAREN_OPEN

--- Called when a closing bracket is detected in function declaration
-- This is a callback assigned in checks
-- like (
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_FPAREN_CLOSE(text, parent)
   if parent == "FUNC_DEF" then
      if FUNC_DEF > 3 then
	 warn("P;A function: " .. FUNCTION .. " accepts more than 4 parameters.")
	 FUNC_DEF = nil
      end
   end
   if parent == "FUNC_PROTO" then FUNC_PROTO = nil end
end

checks["FPAREN_CLOSE"] = c_FPAREN_CLOSE

--- Called when a comma detected
-- This is a callback assigned in checks
-- like ,
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_COMMA(text)
   if FUNC_DEF ~= nil then FUNC_DEF = FUNC_DEF + 1 end
end

checks["COMMA"] = c_COMMA

--- Called when a function call is detected
-- This is a callback assigned in checks
-- like lol()
-- This is important to log function calls for static qualifier checks!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_FUNC_CALL(text)
   table.insert(FUNC_CALL, {id = text, file = FILE})
end

checks["FUNC_CALL"] = c_FUNC_CALL

--- Called when a type is detected
-- This is a callback assigned in checks
-- like int, char, t_context..
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_TYPE(text, parent)
   if parent ~= "C_CAST" and parent ~= "STRUCT" and SIZEOF == nil then
      ASSIGN = true
      if c.isType(text) then return end
      if not (text:starts("t_") or text:starts("s_")) then
	 TYPEStoADD = {id = text, obj = {f = FILE, l = LINE}}
      end
   end
end

checks["TYPE"] = c_TYPE

--- Called when a brace close is detected
-- This is a callback assigned in checks
-- like }
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_BRACE_CLOSE(text, parent)
   if parent == "FUNC_DEF" then
      if FUNCTION_LEN > 26 then warn("L;A function: " .. FUNCTION .. " is longer than 25 lines") end
      FUNCTION_LEN = nil
      FUNCTION = nil
   end
   if parent == "STRUCT" then STRUCT = nil end
end

checks["BRACE_CLOSE"] = c_BRACE_CLOSE

--- Called when a brace open is detected
-- This is a callback assigned in checks
-- like {
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_BRACE_OPEN(text, parent)
   if parent == "STRUCT" then STRUCT = "STRUCT" end
   if parent == "FUNC_DEF" then FUNCTION_LEN = 0 end
end

checks["BRACE_OPEN"] = c_BRACE_OPEN

--- Called when a for is detected
-- This is a callback assigned in checks
-- like for
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_FOR(text, parent)
   warn("K:A function: " .. FUNCTION .. " uses for keyword.")
end

checks["FOR"] = c_FOR

--- Called when a line comment is detected
-- This is a callback assigned in checks
-- like /* ** */
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_COMMENT(text, parent)
   if FUNCTION ~= nil then
      warn("C;A function: " .. FUNCTION .. " contains a comment.")
   end
end

checks["COMMENT"] = c_COMMENT

--- Called when a multi line comment is detected
-- This is a callback assigned in checks
-- like /* ** */
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_COMMENT_MULTI(text, parent)
   if FUNCTION ~= nil then
      warn("C;A function: " .. FUNCTION .. " contains multi lines comment.")
   end
end

checks["COMMENT_MULTI"] = c_COMMENT_MULTI

--- Called when a single line comment is detected
-- This is a callback assigned in checks
-- like //
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_COMMENT_CPP(text, parent)
   if FUNCTION ~= nil then
      warn("C;A function: " .. FUNCTION .. " contains cpp styles comment.")
   end
end

checks["COMMENT_CPP"] = c_COMMENT_CPP

--- Called when a switch is detected
-- This is a callback assigned in checks
-- like switch
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_SWITCH(text, parent)
   warn("K;A function: " .. FUNCTION .. " uses switch keyword.")
end

checks["SWITCH"] = c_SWITCH

--- Called when a continue is detected
-- This is a callback assigned in checks
-- like continue
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_CONTINUE(text, parent)
   warn("K;A function: " .. FUNCTION .. " uses continue keyword.")
end

checks["CONTINUE"] = c_CONTINUE

--- Called when a do while is detected
-- This is a callback assigned in checks
-- like do {} while ()
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_WHILE_OF_DO(text, parent)
   warn("K;A function: " .. FUNCTION .. " uses do while conditionnal loop.")
end

checks["WHILE_OF_DO"] = c_WHILE_OF_DO

--- Called when a break is detected
-- This is a callback assigned in checks
-- like break
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_BREAK(text, parent)
   warn("K;a function: " .. FUNCTION .. " uses break keyword.")
end

--checks["BREAK"] = c_BREAK

--- Called when a goto is detected
-- This is a callback assigned in checks
-- like goto
-- restricted keyword!
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_GOTO(text, parent)
   warn("K;A function: " .. FUNCTION .. " uses goto keyword.")
end

checks["GOTO"] = c_GOTO

--- Called when a preprocessor include is detected
-- This is a callback assigned in checks
-- like #include "lol.h"
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_PP_INCLUDE(text, parent)
   include = true
end

checks["PP_INCLUDE"] = c_PP_INCLUDE

--- Called when a preprocessor if is detected
-- This is a callback assigned in checks
-- like #ifndef
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_PP_IF()
   if include_double == 0 then
      include_double = 1
   end
   include_d = true
end

checks["PP_IF"] = c_PP_IF

--- Called when a string is detected
-- This is a callback assigned in checks
-- like "lol.h"
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_STRING(text)
   if include then
      if text:starts("\"") then
	 include_perso = true
      elseif text:starts("<") then
	 if include_perso then
	    warn("I;A system include : " .. text .. " should be before personnal includes.")
	 end
      end
      include = false
   end
end

checks["STRING"] = c_STRING

--- Called when a return is detected
-- This is a callback assigned in checks
-- @return nothing
-- @param text token text
-- @param parent parent token
function c_RETURN(text)
   RETURN = 0
end

checks["RETURN"] = c_RETURN

function c_PAREN_OPEN(text)
   RETURN = nil
end

checks["PAREN_OPEN"] = c_PAREN_OPEN